/**
 * 
 */
package com.net.job;

import java.io.IOException;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.stereotype.Service;

import com.net.model.Pack;
import com.net.service.pack.PackageService;
import com.net.util.FlowStatUtil;

import jpcap.JpcapCaptor;
import jpcap.NetworkInterface;
import jpcap.packet.ARPPacket;
import jpcap.packet.EthernetPacket;
import jpcap.packet.IPPacket;
import jpcap.packet.Packet;
import jpcap.packet.TCPPacket;
import jpcap.packet.UDPPacket;

/**
 *
 * @author fengcheng
 * @date 2018年6月23日 下午12:44:53
 */
@Service
public class Monitor implements ServletContextListener {
	private MyThread myThread;

	public void contextDestroyed(ServletContextEvent e) {
		if (myThread != null && myThread.isInterrupted()) {
			myThread.interrupt();
		}
	}

	public void contextInitialized(ServletContextEvent e) {
		String str = null;
		if (str == null && myThread == null) {
			myThread = new MyThread();
			myThread.start(); // servlet 上下文初始化时启动 socket
		}
	}
}

/**
 * 自定义一个 Class 线程类继承自线程类，重写 run() 方法，用于从后台获取并处理数据
 *
 * @author Champion.Wong
 *
 */
class MyThread extends Thread {
	private static ApplicationContext ac = new ClassPathXmlApplicationContext(new String[] {
			"classpath:spring/ApplicationContext.xml", "classpath:spring/ApplicationContext-service.xml" });

	public void run() {
		PackageService packageService = (PackageService) ac.getBean("packageService");
		/*--------------    第一步绑定网络设备       --------------*/
		NetworkInterface[] devices = JpcapCaptor.getDeviceList();

		for (NetworkInterface n : devices) {
			String value = "";
			for (int i = 0; i < n.mac_address.length; i++) {
				String sTemp = Integer.toHexString(0xFF & n.mac_address[i]);
				value = value + sTemp + ":";
			}

			value = value.substring(0, value.lastIndexOf(":"));
			System.out.println(n.name + "     |     " + n.description + "     |     " + value);
		}
		System.out.println("-------------------------------------------");

		JpcapCaptor jpcap = null;
		int caplen = 1512;
		boolean promiscCheck = true;

		try {
			jpcap = JpcapCaptor.openDevice(devices[2], caplen, promiscCheck, 50);
		} catch (IOException e) {
			e.printStackTrace();
		}
		/*----------第二步抓包-----------------*/
		while (true) {
			Packet packet = jpcap.getPacket();
			/* ARP */
			if (packet instanceof ARPPacket) {
				Pack pack = new Pack();
				pack.setNet_protocol("ARP");
				ARPPacket arp = (ARPPacket) packet;
				pack.setSrc_mac(arp.getSenderHardwareAddress().toString());
				String src_ip=arp.getSenderProtocolAddress().toString().substring(1);
				pack.setSrc_ip(src_ip);
				pack.setDst_ip(arp.getTargetProtocolAddress().toString());
				String dst_ip=arp.getTargetHardwareAddress().toString().substring(1);
				pack.setDst_mac(dst_ip);
				int len=arp.len;
				pack.setPacket_len(len);
				FlowStatUtil.flowStat(src_ip, dst_ip, len);
				packageService.add(pack);
			}

			if (packet instanceof IPPacket) {
				IPPacket ipPacket = (IPPacket) packet;
				Pack pack = new Pack();

				String protocol = "";
				switch (new Integer(ipPacket.protocol)) {
				case 1:
					protocol = "ICMP";
					break;
				case 2:
					protocol = "IGMP";
					break;
				case 4:
					protocol = "IPv4";
					break;
				case 6:
					protocol = "TCP";
					pack.setTra_protocol(protocol);
					break;
				case 8:
					protocol = "EGP";
					break;
				case 9:
					protocol = "IGP";
					break;
				case 17:
					protocol = "UDP";
					pack.setTra_protocol(protocol);
					break;
				case 41:
					protocol = "IPv6";
					break;
				case 89:
					protocol = "OSPF";
					break;
				default:
					break;
				}
				pack.setNet_protocol(protocol);
				String src_ip=ipPacket.src_ip.getHostAddress();
				pack.setSrc_ip(src_ip);
				String dst_ip=ipPacket.dst_ip.getHostAddress();
				pack.setDst_ip(dst_ip);
				// MAC地址
				EthernetPacket ethPacket = (EthernetPacket) ipPacket.datalink;
				pack.setSrc_mac(ethPacket.getSourceAddress());
				pack.setDst_mac(ethPacket.getDestinationAddress());
				int len=ipPacket.len;
				pack.setPacket_len(len);
				if (packet instanceof TCPPacket) {
					TCPPacket tcp = (TCPPacket) packet;
					pack.setSrc_port(tcp.src_port);
					protocol=null;
					protocol=getProtocolByPort(tcp.src_port);
					if(protocol!=null){
						pack.setApp_protocol(protocol);
					}
					pack.setDst_port(tcp.dst_port);
					protocol=getProtocolByPort(tcp.dst_port);
					if(protocol!=null){
						pack.setApp_protocol(protocol);
					}

				} else if (packet instanceof UDPPacket) {
					UDPPacket udp = (UDPPacket) packet;
					pack.setSrc_port(udp.src_port);
					protocol=null;
					protocol=getProtocolByPort(udp.src_port);
					if(protocol!=null){
						pack.setApp_protocol(protocol);
					}
					pack.setDst_port(udp.dst_port);
					protocol=getProtocolByPort(udp.dst_port);
					if(protocol!=null){
						pack.setApp_protocol(protocol);
					}
				}
				FlowStatUtil.flowStat(src_ip , dst_ip, len);
				packageService.add(pack);
			}
		}
	}

	private String getProtocolByPort(int port) {
		String protocol = null;
		switch (port) {
		case 20:
			protocol = "FTP";
			break;
		case 21:
			protocol = "FTP";
			break;
		case 23:
			protocol = "TELNET";
			break;
		case 25:
			protocol = "SMTP";
			break;
		case 53:
			protocol = "DNS";
			break;
		case 69:
			protocol = "TFTP ";
			break;
		case 67:
			protocol = "DHCP ";
			break;
		case 80:
			protocol = "HTTP";
			break;
		case 109:
			protocol = "POP2";
			break;
		case 110:
			protocol = "POP3";
			break;
		case 111:
			protocol = "RPC";
			break;
		case 123:
			protocol = "NTP";
			break;
		case 143:
			protocol = "IMAP";
			break;
		case 161:
			protocol = "SNMP";
			break;
		case 443:
			protocol = "HTTPS";
			break;
		case 500:
			protocol = "ipsec";
			break;
		case 1645:
			protocol = "RADIUS";
			break;
		case 1701:
			protocol = "L2TP";
			break;
		case 1723:
			protocol = "PPTP";
			break;
		default:
			break;
		}
		return protocol;
	}
}